#ifndef AUDIOENGINE_HPP
#define AUDIOENGINE_HPP

#include <QtCore/QThread>
#include <QtCore/QQueue>
#include "model/AudioFile.hpp"
#include "mod/decoder/Decoder.hpp"
#include "mod/decoder/PcmDecoder.hpp"
#include "mod/decoder/VorbisDecoder.hpp"
#include "mod/decoder/MpgDecoder.hpp"

enum EngineState {
    ENGINE_PLAYING,
    ENGINE_PAUSED,
    ENGINE_STOPPED //buffer is empty
};

/** @brief The AudioEngine class have been created to solve playback "jumps" by creating
 * a bigger and circular buffer.
 */
class AudioEngine : public QThread {
    Q_OBJECT
    private:
        /// @brief Playback channels
        unsigned short channels;
        /// @brief playback samplerate
        unsigned int samplerate;
        /// @brief Audio buffer
        float *buffer;
        /// @brief Buffer size: size=N*channels*paFramesPerBuffer
        unsigned int size;
        /// @brief Position in buffer
        unsigned int position;
        /// @brief If the audio buffer is ready
        bool ready;
        /// @brief Playback state
        int state;
        QQueue<AudioFile*> queue;
        /// @brief Start the thread to fill buffer with decoded audio data
        void run();
    public:
        /** @brief Create an AudioEngine object.
         * @param f Frame count
         * @param c Channel count
         * @param r Output playback samplerate (in Hz)
         */
        AudioEngine(unsigned int f=32768, unsigned short c=2, unsigned int r=44100);
        ~AudioEngine();
        /** @brief Fill the given output buffer. If the state is paused, it will return the output buffer with silence
         * @param output Output buffer
         * @param length Output buffer length
         * @return The size of the data provided or -1 on error
         */
        int fillOutputBuffer(float* output, unsigned int length);
        void seekFrame(unsigned int f);
        void seekTime(unsigned int ms);
    public slots:
        /** @brief Play immediatetly the given audio file.
         * @param af AudioFile object
         */
        void playImmediatetly(AudioFile *af);
        /** @brief Give the next file to play
         * @param af AudioFile object
         */
        void nextFile(AudioFile *af);
        /** @brief Set the state to ENGINE_PAUSED or ENGINE_PLAYING depending on the current state value
         */
        void togglePause();
        /** @brief stop Change state to ENGINE_STOPPED and clear buffer.
         */
        void stop();
        /** @brief Set the state to playing. Depending on the state, it will do different actions:
         * @list
         * @li state=ENGINE_PAUSED: the state value will become ENGINE_PLAYING so the playback will continue
         * @li state=ENGINE_STOPPED: fill completely the buffer with decoded data. It will start the thread but the playback can start when the variable ready is true
         * @endlink
         */
        void play();
    signals:

};

#endif // AUDIOENGINE_HPP
